
using Boilen.Primitives.CodeGeneration;
using Boilen.Primitives.Members;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Xunit;
using Xunit.Extensions;


namespace Boilen.Primitives.Implementers {

    public class TestProperty {

        [Theory]
        [InlineData( null )]
        [InlineData( "" )]
        [InlineData( "default value" )]
        public void SetDefaultExpression_updates_DefaultValue_for_string_values( string expectedValue ) {
            var parent = new PartialType( typeof( SourceClass ) );
            var property = new PropertyCtor<int>( parent, "name", "description" );

            var returnedProperty = property.SetDefaultExpression( expectedValue );

            Assert.Same( returnedProperty, property );
            CheckDefaultValue( property.DefaultValues, expectedValue );
        }

        [Theory]
        [InlineData( null )]
        [InlineData( 1.2 )]
        [InlineData( -1 )]
        [InlineData( "" )]
        [InlineData( "default value" )]
        public void SetDefaultValue_updates_DefaultValue_for_typed_values( object value ) {
            var parent = new PartialType( typeof( SourceClass ) );
            string expectedValue = parent.TypeRepository.GetValueString( value, false );
            var property = new PropertyCtor<object>( parent, "name", "description" );

            var returnedProperty = property.SetDefaultValue( value );

            Assert.Same( returnedProperty, property );
            CheckDefaultValue( property.DefaultValues, expectedValue );
        }

        [Theory]
        [InlineData( DateTimeKind.Local )]
        [InlineData( DateTimeKind.Utc )]
        public void SetDefaultValue_updates_DefaultValue_for_typed_enum_values( DateTimeKind value ) {
            var parent = new PartialType( typeof( SourceClass ) );
            string expectedValue = value.GetType( ).Name + "." + value.ToString( );
            var property = new PropertyCtor<DateTimeKind>( parent, "name", "description" );

            var returnedProperty = property.SetDefaultValue( value );

            Assert.Same( returnedProperty, property );
            CheckDefaultValue( property.DefaultValues, expectedValue );
        }

        [Theory]
        [InlineData( BindingFlags.NonPublic )]
        [InlineData( BindingFlags.Public | BindingFlags.Static )]
        public void SetDefaultValue_updates_DefaultValue_for_typed_flag_enum_values( BindingFlags value ) {
            var parent = new PartialType( typeof( SourceClass ) );
            string expectedValue = parent.TypeRepository.GetValueString( value, false );
            var property = new PropertyCtor<BindingFlags>( parent, "name", "description" );

            var returnedProperty = property.SetDefaultValue( value );

            Assert.Same( returnedProperty, property );
            CheckDefaultValue( property.DefaultValues, expectedValue );
        }


        #region Utility

        private static void CheckDefaultValue( Dictionary<CompilationSymbol, string> defaultValues, string expectedValue ) {
            var dv = Assert.Single( defaultValues );
            Assert.Equal( dv.Key, CompilationSymbol.None );
            Assert.Equal( dv.Value, expectedValue );
        }


        private sealed class PropertyCtor<T> : Property<T> {
            protected override IEnumerable<InitializationMember> Initializers { get { throw new NotImplementedException( ); } }
            protected override AccessorMember Accessor { get { throw new NotImplementedException( ); } }
            public PropertyCtor( PartialType parent, string name, string description ) : base( parent, name, description ) { }
        }

        #endregion

    }

}
